package com.naiterui.ehp.bs.pharmacist.utils;

import com.naiterui.common.redis.RedisUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

/**
 * Redis分布式锁操作类
 *
 * @author fangguanhong
 * @since 1.0.0
 */
public class RedisLock {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisLock.class);
    // 存储redis锁标志
    private static final String LOCKED = "TRUE";
    // 超时（毫秒）
    private static final long TIME_OUT = 5000;
    // 锁到期时间（秒）
    public static final int EXPIRE = 60;
    // redis存储key
    private String key;
    // 状态标志
    private volatile boolean locked = false;
    // private static ConcurrentMap<String, RedisLock> map = new ConcurrentHashMap<String,
    // RedisLock>();

    public RedisLock(String key) {
        this.key = "_LOCK_" + key;
    }

    public static RedisLock getInstance(String key) {
        // return map.getOrDefault(key, new RedisLock(key));
        return new RedisLock(key);
    }

    public boolean lock(long timeout) {
        long nano = System.nanoTime();
        Random r = new Random();
        timeout *= 1000000;
        try {
            while ((System.nanoTime() - nano) < timeout) {
                // SETNX key value 功能： 当且仅当 key 不存在，将 key 的值设为 value ，并返回1；若给定的 key 已经存在，则 SETNX
                // 不做任何动作，并返回0。 有了以上Redis知识了，写个简单的分布式锁就不是什么难事。
                if (1 == RedisUtil.valueOps().setNx(key, LOCKED)) {
                    RedisUtil.keyOps().expire(key, EXPIRE);
                    locked = true;
                    LOGGER.debug("add RedisLock[" + key + "].");
                    break;
                }
                Thread.sleep(600, r.nextInt(500));
            }
        } catch (Exception e) {
        }
        return locked;
    }

    public boolean lock() {
        return this.lock(TIME_OUT);
    }

    public void unlock() {
        if (locked) {
            LOGGER.debug("release RedisLock[" + key + "].");
            RedisUtil.keyOps().delete(key);
        }
    }

    /**
     * 返回当前是否存在锁
     * RedisLock.isLocked()
     *
     * @return
     *
     * @Author guoyongxiang
     * @Date 2016年7月5日
     * @since 1.0.0
     */
    public boolean isLocked() {
        return RedisUtil.keyOps().existsKey(key);
    }

    public void lockInterruptibly() {

    }

    public Condition newCondition() {
        return null;
    }

    public boolean tryLock() {
        return false;
    }

    public boolean tryLock(long time, TimeUnit unit) {
        return false;
    }

}
